package msg_center

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"git.mycaigou.com/gfyx/common/http_client"
	"git.myscrm.cn/golang/stark/v4"
	"time"
)

type MsgServiceIface interface {
	getMsgAccessToken(ctx context.Context, appCode string, appSecret string) (string, error)
	Push(ctx context.Context, msgBody *MsgBody) error
}

func NewClient(config *MsgClientConfig) (client *Client) {
	if config == nil {
		config = &MsgClientConfig{
			AppCode:   stark.Configer.(stark.ApolloConfigerIface).GetStringValue("MsgService.AppCode", ""),
			AppSecret: stark.Configer.(stark.ApolloConfigerIface).GetStringValue("MsgService.AppSecret", ""),
			Host:      stark.Configer.(stark.ApolloConfigerIface).GetStringValue("MsgService.Host", ""),
		}
	}
	return &Client{
		appCode:   config.AppCode,
		appSecret: config.AppSecret,
		host:      config.Host,
	}
}

// Push 推送通知
func (c *Client) Push(ctx context.Context, msgBody *MsgBody) error {
	token, err := c.getMsgAccessToken(ctx, c.appCode, c.appSecret)
	//fmt.Printf("----------token: %#v | err: %#v\n", token, err)
	if err != nil {
		return err
	}
	if token == "" {
		return errors.New("access-token为空")
	}

	if msgBody == nil {
		return errors.New("参数为空")
	}
	// 校验消息内容是否为json格式
	msgBody.AccessToken = token
	err = c.checkMsgContent(msgBody)
	if err != nil {
		return err
	}
	fmt.Printf("推送内容 > [%#v]\n", msgBody)
	pushUrl := c.host + "/v1/message/send-push-order"
	for try := 0; try < 2; try++ {
		resultMap := map[string]interface{}{}
		httpClient := http_client.New()
		httpClient.Post(ctx, pushUrl, msgBody, map[string]string{})
		httpClient.EndStruct(&resultMap)

		if resultMap != nil && !resultMap["success"].(bool) && resultMap["error_code"].(string) == "401" {
			fmt.Printf("推送失败[try:%d] > [%#v]\n", try, resultMap)
			token, err = c.getMsgAccessToken(ctx, c.appCode, c.appSecret)
			if err != nil {
				return err
			}
		} else {
			fmt.Printf("推送成功[try:%d] > [%#v]\n", try, resultMap)
			break
		}
	}

	return nil
}

// 获取消息推送access-token
func (c *Client) getMsgAccessToken(ctx context.Context, appCode string, appSecret string) (string, error) {
	c.accessTokenLock.Lock()
	defer c.accessTokenLock.Unlock()
	if c.accessToken != "" && time.Now().Sub(c.tokenTime) < time.Hour {
		return c.accessToken, nil
	}
	msgClientParams := &msgClientParams{
		AppCode:   appCode,
		AppSecret: appSecret,
	}
	return c.getNewAccessToken(ctx, msgClientParams)
}

func (c *Client) getNewAccessToken(ctx context.Context, msgClientParams *msgClientParams) (string, error) {
	//todo: 读缓存，获取token
	data := map[string]interface{}{
		"app_code":   msgClientParams.AppCode,
		"app_secret": msgClientParams.AppSecret,
	}
	authUrl := c.host + "/v1/login/access-token"
	fmt.Printf("获取token url:%s, params:%+v\n", authUrl, data)

	resultMap := map[string]interface{}{}
	httpClient := http_client.New()
	httpClient.Post(ctx, authUrl, data, map[string]string{})
	httpClient.EndStruct(&resultMap)

	if resultMap != nil && !resultMap["success"].(bool) {
		fmt.Printf("获取推送token失败 > [%#v]", resultMap)
		return "", errors.New(fmt.Sprintf("获取推送token失败 > [%#v]", resultMap))
	}
	if rtoken, ok := resultMap["data"].(map[string]interface{})["token"]; ok {
		//todo: 缓存token
		c.accessToken = rtoken.(string)
		c.tokenTime = time.Now()
		return c.accessToken, nil
	} else {
		return "", nil
	}
}

//
// 格式化请求结果
//
func (c *Client) formatResult(r string) (map[string]interface{}, error) {
	var resultMap map[string]interface{}
	err := json.Unmarshal([]byte(r), &resultMap)
	if err != nil {
		return nil, err
	}
	return resultMap, nil
}

func (c *Client) checkMsgContent(msgBody *MsgBody) error {
	if msgBody.PushOrderCode == "" {
		return errors.New("push_order_code为空")
	}
	if msgBody.Wx != nil && msgBody.Wx.ReceiverIds != nil && msgBody.Wx.Content != "" {
		var contentMap map[string]interface{}
		err := json.Unmarshal([]byte(msgBody.Wx.Content), &contentMap)
		if err != nil {
			fmt.Printf("wx渠道content Json串转化为失败,异常:%s\n", err)
			return err
		}
	}
	if msgBody.Site != nil && msgBody.Site.ReceiverIds != nil && msgBody.Site.Content != "" {
		var contentMap map[string]interface{}
		err := json.Unmarshal([]byte(msgBody.Site.Content), &contentMap)
		if err != nil {
			fmt.Printf("wx渠道content Json串转化为失败,异常:%s\n", err)
			return err
		}
	}
	if msgBody.Sms != nil && msgBody.Sms.ReceiverIds != nil && msgBody.Sms.Content != "" {
		var contentMap map[string]interface{}
		err := json.Unmarshal([]byte(msgBody.Sms.Content), &contentMap)
		if err != nil {
			fmt.Printf("Sms渠道content Json串转化为失败,异常:%s\n", err)
			return err
		}
	}
	if msgBody.Email != nil && msgBody.Email.ReceiverIds != nil && msgBody.Email.Content != "" {
		var contentMap map[string]interface{}
		err := json.Unmarshal([]byte(msgBody.Email.Content), &contentMap)
		if err != nil {
			fmt.Printf("Email渠道content Json串转化为失败,异常:%s\n", err)
			return err
		}
	}
	return nil
}
